<template>
  <div class="container">
    <div class="toolbar">
      <el-button type="primary" @click="enableDrawRect">绘制矩形</el-button>
      <el-button type="primary" @click="addText">添加文字说明</el-button>
      <el-button type="danger" @click="deleteSelected">删除</el-button>
      <el-button type="danger" @click="clearCanvas">清空</el-button>
      <el-upload
        action=""
        :show-file-list="false"
        :before-upload="handleImageUpload"
      >
        <el-button type="primary">上传待标注图片</el-button>
      </el-upload>
    </div>
    <div class="canvas-box">
      <canvas ref="fabricCanvas" id="fabricCanvas" />
      <div class="operate-box">
        <el-form
          v-for="(labelData, index) in labelDataList"
          :model="labelData"
          label-width="auto"
          :key="index"
        >
          <el-form-item label="标注id" class="form-item-flex">
            <el-input v-model="labelData.uid" disabled class="disbaled-input" />
          </el-form-item>
          <el-form-item label="标注位置" class="form-item-flex">
            <el-col :span="2">x: </el-col>
            <el-col :span="10">
              <el-input
                v-model="labelData.positionX"
                disabled
                class="disbaled-input"
              />
            </el-col>
            <el-col :span="2">y: </el-col>
            <el-col :span="10">
              <el-input
                v-model="labelData.positionY"
                disabled
                class="disbaled-input"
              />
            </el-col>
          </el-form-item>
          <el-form-item label="标注大小">
            <el-col :span="4">width: </el-col>
            <el-col :span="8">
              <el-input
                v-model="labelData.width"
                disabled
                class="disbaled-input"
              />
            </el-col>
            <el-col :span="4">height: </el-col>
            <el-col :span="8">
              <el-input
                v-model="labelData.height"
                disabled
                class="disbaled-input"
              />
            </el-col>
          </el-form-item>
          <el-form-item label="标注类型">
            <!-- <el-select v-model="labelData.type" placeholder="选择标注类型">
              <el-option label="A" value="A" />
              <el-option label="B" value="B" />
            </el-select> -->
            <el-input v-model="labelData.type" />
          </el-form-item>
          <el-form-item label="备注说明">
            <el-input v-model="labelData.remarks" />
          </el-form-item>

          <el-divider />
        </el-form>
        <div v-if="labelDataList.length > 0" class="submit-button">
          <el-button type="primary" @click="onSubmit">提交</el-button>
          <el-button>取消</el-button>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { onMounted, reactive, ref } from 'vue'
import * as fabric from 'fabric'
import { generateUUID } from '@/utils'

let canvas = null
let isDrawing = false // 是否正在绘制矩形
let canDraw = false // 是否启用绘制功能
let currentRect = null // 当前正在绘制的矩形
let startX = 0
let startY = 0

const fabricCanvas = ref(null)
const labelDataList = reactive([])
// 初始化Fabric.js的canvas
const initCanvas = () => {
  const canvasElement = fabricCanvas.value
  // 使用 canvas 元素的宽度和高度进行初始化
  const canvasWidth = canvasElement.offsetWidth // 获取 canvas 元素的宽度
  const canvasHeight = canvasElement.offsetHeight // 获取 canvas 元素的高度
  canvas = new fabric.Canvas('fabricCanvas', {
    width: canvasWidth,
    height: canvasHeight,
    backgroundColor: '#f3f3f3'
  })

  // 监听对象修改事件，获取最新的矩形大小和位置
  canvas.on('object:modified', (e) => {
    const modifiedObject = e.target
    if (modifiedObject && modifiedObject.type === 'rect') {
      const rectInfo = {
        x: modifiedObject.left,
        y: modifiedObject.top,
        width: modifiedObject.width * modifiedObject.scaleX, // 由于可能有缩放，所以需要乘以缩放值
        height: modifiedObject.height * modifiedObject.scaleY
      }
      labelData.positionX = rectInfo.x
      labelData.positionY = rectInfo.y
      labelData.width = rectInfo.width
      labelData.height = rectInfo.height
      console.log('矩形修改后的位置和大小:', rectInfo)
    }
  })
}
// 启用绘制矩形功能
const enableDrawRect = () => {
  const labelData = {}
  canDraw = true // 允许开始绘制矩形
  labelData.uid = generateUUID()
  canvas.isDrawingMode = false // 禁用 Fabric.js 的自由绘制模式
  canvas.off('mouse:down')
  canvas.off('mouse:move')
  canvas.off('mouse:up')

  // 鼠标按下事件，开始绘制
  canvas.on('mouse:down', (options) => {
    if (!canDraw) return // 如果不允许绘制，直接返回
    const pointer = canvas.getPointer(options.e)
    isDrawing = true
    startX = pointer.x
    startY = pointer.y

    // 创建初始大小为0的矩形
    currentRect = new fabric.Rect({
      left: startX,
      top: startY,
      width: 0,
      height: 0,
      fill: 'rgba(0,0,0,0.3)',
      stroke: 'black',
      strokeWidth: 1
    })
    canvas.add(currentRect)
  })

  // 鼠标移动事件，更新矩形大小
  canvas.on('mouse:move', (options) => {
    if (!isDrawing) return // 如果没有开始绘制，直接返回
    const pointer = canvas.getPointer(options.e)

    // 计算并设置矩形的宽度和高度
    const width = Math.abs(pointer.x - startX)
    const height = Math.abs(pointer.y - startY)

    // 更新矩形的位置和大小
    currentRect.set({
      width: width,
      height: height,
      left: pointer.x < startX ? pointer.x : startX,
      top: pointer.y < startY ? pointer.y : startY
    })
    canvas.renderAll()
  })

  // 鼠标抬起事件，结束绘制
  canvas.on('mouse:up', () => {
    if (isDrawing && currentRect) {
      isDrawing = false // 停止绘制
      canDraw = false // 禁用绘制，必须再次点击按钮才可以绘制

      const rectInfo = {
        x: currentRect.left,
        y: currentRect.top,
        width: currentRect.width,
        height: currentRect.height
      }
      console.log('绘制后的矩形信息:', rectInfo) // 输出矩形位置信息
      // 给标注表单赋值
      labelData.positionX = rectInfo.x
      labelData.positionY = rectInfo.y
      labelData.width = rectInfo.width
      labelData.height = rectInfo.height
      labelDataList.push(labelData)

      // 解除事件监听
      canvas.off('mouse:down')
      canvas.off('mouse:move')
      canvas.off('mouse:up')
    }
  })
}
// 添加文本标注
const addText = () => {
  const text = new fabric.Textbox('请输入文字', {
    left: 200,
    top: 150,
    width: 200,
    fontSize: 20,
    fill: 'black'
  })
  canvas.add(text)
}

// 删除选中的对象
const deleteSelected = () => {
  const activeObject = canvas.getActiveObject()
  if (activeObject) {
    canvas.remove(activeObject)
  }
}

// 清空画布
const clearCanvas = () => {
  canvas.clear()
  // canvas.setBackgroundColor('#f3f3f3', canvas.renderAll.bind(canvas))
  canvas.backgroundColor = '#f3f3f3'; // 设置背景颜色为红色
  canvas.renderAll(); // 强制重新渲染
  labelDataList.splice(0, labelDataList.length);
}

// 上传图片并设置为背景
const handleImageUpload = (file) => {
  const reader = new FileReader(file)

  // 文件读取完成后加载图片
  reader.onload = (f) => {
    const data = f.target.result

    // 创建Image对象手动加载
    const img = new Image()
    img.src = data
    img.onload = () => {
      // 获取canvas的宽高
      const c = fabricCanvas.value
      const canvasRect = c.getBoundingClientRect()
      const canvasWidth = canvasRect.width
      const canvasHeight = canvasRect.height
      console.log('canvasWidth:', canvasWidth, 'canvasHeight:', canvasHeight)

      // 获取图片的宽高
      const imgWidth = img.width
      const imgHeight = img.height

      // 计算图片和画布的宽高比
      const canvasAspect = canvasWidth / canvasHeight
      const imgAspect = imgWidth / imgHeight
      console.log(canvasAspect, 'imgAspect:', imgAspect)

      let scale, left, top

      // 根据宽高比调整图片的缩放比例
      if (imgAspect > canvasAspect) {
        // 图片宽度大于画布宽度比例时，以高度为基准
        scale = canvasWidth / imgWidth
        top = (canvasHeight - imgHeight * scale) / 2 // 居中对齐
        left = 0
      } else {
        scale = canvasHeight / imgHeight
        left = (canvasWidth - imgWidth * scale) / 2 // 居中对齐
        top = 0
      }

      const fabricImg = new fabric.Image(img, {
        left: left,
        top: top,
        scaleX: scale,
        scaleY: scale,
        selectable: false // 背景图片不可以选中
      })

      // 直接设置背景图片属性
      canvas.backgroundImage = fabricImg
      canvas.renderAll() // 重新渲染画布
    }
  }

  // 读取图片文件
  reader.readAsDataURL(file)

  // 阻止文件自动上传
  return false
}

const onSubmit = (form) => {
  console.log(form)
}
onMounted(() => {
  initCanvas()
})
</script>

<style scoped lang="scss">
.toolbar {
  display: flex;
  margin-bottom: 10px;
  background-size: cover;
}

button {
  margin-right: 10px;
}
.canvas-box {
  display: flex;
  justify-content: space-between;
  height: calc(100vh - 250px);
  #fabricCanvas {
    width: 75%;
    height: 100%;
    border: 1px solid var(--el-border-color);
  }
  .operate-box {
    width: 20%;
    border: 1px solid var(--el-border-color);
    padding: 16px;
    text-align: center;
  }
  .form-item-flex {
    display: flex;
  }
  :deep(.el-input.is-disabled .el-input__inner) {
    color: #000;
    -webkit-text-fill-color: #000;
  }
  .disbaled-input {
    color: #fff;
  }
}
</style>
